import { Injectable } from '@angular/core'
import { Router } from '@angular/router'
import { Http, Response } from '@angular/http'
import { Action } from '@ngrx/store'
import { Effect, Actions, ofType } from '@ngrx/effects'
import { Observable } from 'rxjs/Observable'
import { NzMessageService } from 'ng-zorro-antd'
import { of } from 'rxjs/observable/of'
import { mergeMap, map, tap, catchError } from 'rxjs/operators'
import * as fromChecklist from '../actions/checklist'
import { Functions } from '../../common/functions'

@Injectable()
export class ChecklistEffects {

  //#region [LIST]
  @Effect()
  fetchChecklist$ = this._actions$.pipe(
    ofType<fromChecklist.FetchChecklistAction>(fromChecklist.ChecklistActionTypes.FetchChecklist),
    mergeMap((action) =>
     this._http.get(
       `api/list/${action.payload}`,
       this._funcs.getRequestOptions()).pipe(
          map((res) =>
            new fromChecklist.FetchChecklistSuccessAction(this._funcs.parseData(res))
          ),
          catchError((err) => new Observable(() => {
            const { msg } = this._funcs.handleHttpError(err)
            this._message.error(msg)
          }))
       )
    )
  )

  @Effect()
  addNewList$ = this._actions$.pipe(
    ofType<fromChecklist.AddChecklistAction>(fromChecklist.ChecklistActionTypes.AddNewList),
    mergeMap((action) =>
      this._http.post(
        `api/list`, action.payload,
        this._funcs.getRequestOptions()
      ).pipe(
        map((res) =>
          new fromChecklist.AddChecklistSuccessAction(this._funcs.parseData(res))
        ),
        catchError((err) => new Observable(() => {
          const { msg } = this._funcs.handleHttpError(err)
          this._message.error(msg)
        }))
      )
    )
  )

  @Effect({ dispatch: false })
  addNewListSuccess$ = this._actions$.pipe(
    ofType<fromChecklist.AddChecklistSuccessAction>(fromChecklist.ChecklistActionTypes.AddNewListSuccess),
    tap((action) => this._router.navigate([`/lists/${action.payload.id}`], { queryParams: { newlist: true } }))
  )

  @Effect()
  deleteChecklist$ = this._actions$.pipe(
    ofType<fromChecklist.DeleteChecklistAction>(fromChecklist.ChecklistActionTypes.DeleteList),
    mergeMap((action) =>
      this._http.delete(
        `api/list/${action.payload}`,
        this._funcs.getRequestOptions()
      ).pipe(
        map((res) =>
          new fromChecklist.DeleteChecklistSuccessAction(action.payload)
        ),
        catchError((err) => new Observable(() => {
          const { msg, code } = this._funcs.handleHttpError(err)
          if (code && code === 4005) {
            this._message.error('清单不存在')
          } else {
            this._message.error(msg)
          }
        }))
      )
    )
  )

  @Effect({ dispatch: false })
  deleteChecklistSuccess$ = this._actions$.pipe(
    ofType<fromChecklist.DeleteChecklistSuccessAction>(fromChecklist.ChecklistActionTypes.DeleteListSuccess),
    tap(() => {
      this._message.success('删除成功')
      setTimeout(() => {
        this._router.navigate(['/my-day'])
      }, 1000)
    })
  )

  @Effect()
  renameChecklist$ = this._actions$.pipe(
    ofType<fromChecklist.RenameChecklistAction>(fromChecklist.ChecklistActionTypes.RenameListTitle),
    mergeMap((action) =>
      this._http.put(
        `api/list/title`, action.payload,
        this._funcs.getRequestOptions()
      ).pipe(
        map((res) =>
          new fromChecklist.RenameChecklistSuccessAction(action.payload)
        ),
        catchError((err) => new Observable(() => {
          const { msg } = this._funcs.handleHttpError(err)
          this._message.error(msg)
        }))
      )
    )
  )
  //#endregion

  //#region [TASK]
  @Effect()
  addTodayTask$ = this._actions$.pipe(
    ofType<fromChecklist.AddTodayTaskAction>(fromChecklist.ChecklistActionTypes.AddTodayTask),
    mergeMap((action) =>
      this._http.post(
        `api/task/myday`, action.payload,
        this._funcs.getRequestOptions()
      ).pipe(
        map((res) =>
          new fromChecklist.AddTodayTaskSuccessAction(this._funcs.parseData(res))
        ),
        catchError((err) => new Observable(() => {
          const { msg } = this._funcs.handleHttpError(err)
          this._message.error(msg)
        }))
      )
    )
  )

  @Effect()
  addNewTask$ = this._actions$.pipe(
    ofType<fromChecklist.AddNewTaskAction>(fromChecklist.ChecklistActionTypes.AddNewTask),
    mergeMap((action) =>
      this._http.post(
        `api/task`, action.payload,
        this._funcs.getRequestOptions()
      ).pipe(
        map((res) =>
          new fromChecklist.AddNewTaskSuccessAction({ listId: action.payload.listId, ...this._funcs.parseData(res) })
        ),
        catchError((err) => new Observable(() => {
          const { msg } = this._funcs.handleHttpError(err)
          this._message.error(msg)
        }))
      )
    )
  )

  @Effect()
  deleteTask$ = this._actions$.pipe(
    ofType<fromChecklist.DeleteTaskAction>(fromChecklist.ChecklistActionTypes.DeleteTask),
    mergeMap((action) =>
      this._http.delete(
        `api/task/${action.payload.listId}/${action.payload.index}`,
        this._funcs.getRequestOptions()
      ).pipe(
        map((res) =>
          new fromChecklist.DeleteTaskSuccessAction(action.payload)
        ),
        catchError((err) => new Observable(() => {
          const { msg } = this._funcs.handleHttpError(err)
          this._message.error(msg)
        }))
      )
    )
  )

  @Effect()
  toggleDoneTask$ = this._actions$.pipe(
    ofType<fromChecklist.ToggleDoneTaskActin>(fromChecklist.ChecklistActionTypes.ToggleDoneTask),
    mergeMap((action) =>
      this._http.put(
        `api/task`, action.payload,
        this._funcs.getRequestOptions()
      ).pipe(
        map((res) =>
          new fromChecklist.ToggleDoneTaskSuccessAction(action.payload)
        ),
        catchError((err) => new Observable(() => {
          const { msg } = this._funcs.handleHttpError(err)
          this._message.error(msg)
        }))
      )
    )
  )

  @Effect()
  toggleMydayTask$ = this._actions$.pipe(
    ofType<fromChecklist.ToggleMydayTaskAction>(fromChecklist.ChecklistActionTypes.ToggleMydayTask),
    mergeMap((action) =>
      this._http.put(
        `api/task`, action.payload,
        this._funcs.getRequestOptions()
      ).pipe(
        map((res) =>
          action.payload.today
          ? new fromChecklist.ToggleMydayTaskInSuccessAction(action.payload)
          : new fromChecklist.ToggleMydayTaskOutSuccessAction(action.payload)
        ),
        catchError((err) => new Observable(() => {
          const { msg } = this._funcs.handleHttpError(err)
          this._message.error(msg)
        }))
      )
    )
  )

  @Effect()
  renameTask$ = this._actions$.pipe(
    ofType<fromChecklist.RenameTaskAction>(fromChecklist.ChecklistActionTypes.RenameTask),
    mergeMap((action) =>
      this._http.put(
        `api/task`, action.payload,
        this._funcs.getRequestOptions()
      ).pipe(
        map((res) =>
          new fromChecklist.RenameTaskSuccessAction(action.payload)
        ),
        catchError((err) => new Observable(() => {
          const { msg } = this._funcs.handleHttpError(err)
          this._message.error(msg)
        }))
      )
    )
  )

  @Effect()
  updateTaskNote$ = this._actions$.pipe(
    ofType<fromChecklist.UpdateTaskNoteAction>(fromChecklist.ChecklistActionTypes.UpdateTaskNote),
    mergeMap((action) =>
      this._http.put(
        `api/task`, action.payload,
        this._funcs.getRequestOptions()
      ).pipe(
        map((res) =>
          new fromChecklist.UpdateTaskNoteSuccessAction(action.payload)
        ),
        catchError((err) => new Observable(() => {
          const { msg } = this._funcs.handleHttpError(err)
          this._message.error(msg)
        }))
      )
    )
  )

  @Effect()
  setToBeDoneTomorrow$ = this._actions$.pipe(
    ofType<fromChecklist.SetBeDoneTomorrowAction>(fromChecklist.ChecklistActionTypes.SetBeDoneTomorrow),
    mergeMap((action) =>
      this._http.put(
        `api/task`, action.payload,
        this._funcs.getRequestOptions()
      ).pipe(
        map((res) =>
          new fromChecklist.SetBeDoneTomorrowSuccessAction(action.payload)
        ),
        catchError((err) => new Observable(() => {
          const { msg } = this._funcs.handleHttpError(err)
          this._message.error(msg)
        }))
      )
    )
  )

  @Effect()
  setToBeDoneToday$ = this._actions$.pipe(
    ofType<fromChecklist.SetBeDoneTodayAction>(fromChecklist.ChecklistActionTypes.SetBeDoneToday),
    mergeMap((action) =>
      this._http.put(
        `api/task`, action.payload,
        this._funcs.getRequestOptions()
      ).pipe(
        map((res) =>
          new fromChecklist.SetBeDoneTodaySuccessAction(action.payload)
        ),
        catchError((err) => new Observable(() => {
          const { msg } = this._funcs.handleHttpError(err)
          this._message.error(msg)
        }))
      )
    )
  )

  @Effect()
  clearDeadline$ = this._actions$.pipe(
    ofType<fromChecklist.ClearDeadlineAction>(fromChecklist.ChecklistActionTypes.ClearDeadline),
    mergeMap((action) =>
      this._http.delete(
        `api/task/${action.payload.listId}/${action.payload.index}/deadline`,
        this._funcs.getRequestOptions()
      ).pipe(
        map((res) =>
          new fromChecklist.ClearDeadlineSuccessAction(action.payload)
        ),
        catchError((err) => new Observable(() => {
          const { msg } = this._funcs.handleHttpError(err)
          this._message.error(msg)
        }))
      )
    )
  )

  @Effect()
  moveTask$ = this._actions$.pipe(
    ofType<fromChecklist.MoveTaskAction>(fromChecklist.ChecklistActionTypes.MoveTask),
    mergeMap((action) =>
      this._http.post(
        `/api/task/move`,
        action.payload,
        this._funcs.getRequestOptions()
      ).pipe(
        map((res) =>
          new fromChecklist.MoveTaskSuccessAction(action.payload)
        ),
        catchError((err) => new Observable(() => {
          const { msg } = this._funcs.handleHttpError(err)
          this._message.error(msg)
        }))
      )
    )
  )
  //#endregion

  constructor (
    private _actions$: Actions,
    private _http: Http,
    private _router: Router,
    private _funcs: Functions,
    private _message: NzMessageService
  ) { }
}
